﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Lon.Util
{
    /// <summary>
    /// 本类只适用于增量写入的情况
    /// 
    /// 
    /// </summary>
    public  class DictFile
    {

        #region 路径相关信息

        /// <summary>
        /// 文件名
        /// </summary>
       public String FileName
        {
            get;
            protected set;
        }
        /// <summary>
        ///  文件完整路径
        /// </summary>
       public  String FilePath
        {
            get;
            protected set;
        }
        /// <summary>
        /// 文件路径
        /// </summary>
       public  String FileDirectroy
        {
            get;
            protected set;
        }
        #endregion

       public FileBaseInfo FileBaseInfo
       {
           get;
           protected set;
       }

       /// <summary>
        /// 键值记录
        /// </summary>
        protected Dictionary<int, DictRec> RecDict = new Dictionary<int, DictRec>();

        protected Dictionary<int, DataRec> cacheDict = new Dictionary<int, DataRec>();

        private int CacheSize;

        /// <summary>
        /// 通过文件创建类,类的所有信息通过文件来加载
        /// </summary>
        /// <param name="filePath"></param>
        public DictFile(String filePath)
        {
            InitPathInfo(filePath);
            if (!File.Exists(filePath))
            {
                FileBaseInfo = new FileBaseInfo();
                CreateNewFile();
            }
            else
            {
                this.Load();
            }
        }

        public  void Load()
        {
            FileBaseInfo= new FileBaseInfo();
          
            using (FileStream fs = new FileStream(this.FilePath, FileMode.Open))
            {
                BinaryReader br = new BinaryReader(fs);
                FileBaseInfo.Read(br);
                fs.Seek(FileBaseInfo.Size, SeekOrigin.Begin);
                for (int i = 0; i < FileBaseInfo.DictCount; i++)
                {
                    DictRec dRec = new DictRec();
                    dRec.Read(br);
                    this.RecDict[dRec.Key] = dRec;
                }

            }

        }

        public DictFile(String filePath, int dictSize, int FileSize)
        {
            FileBaseInfo = new FileBaseInfo(FileSize, dictSize);
            InitPathInfo(filePath);
        }



        /// <summary>
        /// 初始化文件夹相关信息
        /// </summary>
        /// <param name="filePath"></param>
        private void InitPathInfo(String filePath)
        {
            this.FilePath = filePath;
            this.FileDirectroy = Path.GetDirectoryName(filePath);
            this.FileName = Path.GetFileName(filePath);
        }

        /// <summary>
        /// 创建新文件
        /// </summary>
        private void CreateNewFile()
        {
          
            if (Directory.Exists(this.FileDirectroy) == false)
            {
                Directory.CreateDirectory(this.FileDirectroy);
            }
            using(FileStream fs=new FileStream(this.FilePath,FileMode.Create))
            {
                BinaryWriter bw = new BinaryWriter(fs);
                FileBaseInfo.Write(bw);
                bw.Seek(FileBaseInfo.FileSize, SeekOrigin.Begin);
                bw.Write("This is End");
                fs.Flush();
            }
        
            
        }

        public void WriteData(int key, byte[] data)
        {
            lock(this)
            {
                if (this.cacheDict.ContainsKey(key))
                {
                    NetDebugConsole.WriteLine("文件[{0}]添加[{1}]", this.FileName, key);

                }
                else
                {
                    DataRec rec = new DataRec();
                    rec.Key = key;
                    rec.Data = data;
                    cacheDict.Add(key, rec);
                    this.CacheSize += data.Length;
                    if (this.CacheSize > 1024 * 1024 * 4)
                    {
                        this.Flush();
                    }
                }

            }
        }

        public byte[] ReadRec(int key)
        {
            if (this.cacheDict.ContainsKey(key))
            {
                return cacheDict[key].Data;
            }
            else
            {
                if (this.RecDict.ContainsKey(key))
                {
                    using (FileStream fs = new FileStream(this.FilePath, FileMode.Open))
                    {
                        fs.Seek(RecDict[key].Offset + FileBaseInfo.DataStartPos, SeekOrigin.Begin);
                        BinaryReader br = new BinaryReader(fs);
                        DataRec dataRec = new DataRec();
                        dataRec.Read(br);
                       
                        fs.Close();
                        return dataRec.Data;
                    }
                }
            }
            return null;
        }

        public void Flush()
        {
            List<DictRec> cacheDictRec = new List<DictRec>();   
            lock (this)
            {
                using (FileStream fs = new FileStream(this.FilePath, FileMode.Open))
                {
                    fs.Seek(FileBaseInfo.CurrWritePoint+FileBaseInfo.DataStartPos,SeekOrigin.Begin);
                    BinaryWriter bw = new BinaryWriter(fs);
                    int beforeWriteDictCount=this.FileBaseInfo.DictCount;
                    foreach (var rec in cacheDict.Values)
                    {
                        if (this.RecDict.ContainsKey(rec.Key))
                        {
                            NetDebugConsole.WriteLine("文件[0]重复写入数据[1]", this.FileName, rec.Key);
                            continue;
                        }
                        rec.Pos = FileBaseInfo.CurrWritePoint;
                        rec.Write(bw);
                        FileBaseInfo.CurrWritePoint += rec.Length;
                        DictRec indexRec = new DictRec(rec.Key, rec.Pos, rec.Length);
                        cacheDictRec.Add(indexRec);
                        this.RecDict.Add(indexRec.Key, indexRec);
                        FileBaseInfo.DictCount++;
                    }
                    if (FileBaseInfo.FileSize < FileBaseInfo.CurrWritePoint)
                    {
                        FileBaseInfo.FileSize = FileBaseInfo.CurrWritePoint + 16 * 1024 * 1024+FileBaseInfo.DataStartPos;
                        fs.Seek(this.FileBaseInfo.FileSize, SeekOrigin.Begin);
                    }
                    fs.Seek(FileBaseInfo.Size+beforeWriteDictCount*12, SeekOrigin.Begin);
                    for (int i = 0; i < cacheDictRec.Count; i++)
                    {
                        cacheDictRec[i].Write(bw);  
                    }
                    this.cacheDict.Clear();
                    fs.Seek(0, SeekOrigin.Begin);
                    FileBaseInfo.Write(bw);
                    fs.Close();
                }
            }
            
        }

        public void Close()
        {
            this.Flush();
        }
      
   

    }
}
